/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.drawee.view;

import com.facebook.common.internal.Objects;
import com.facebook.drawee.drawable.Callback;
import com.facebook.drawee.drawable.RootShapeElement;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.interfaces.DraweeHierarchy;
import com.facebook.imagepipeline.systrace.FrescoSystrace;
import com.oszc.bbhmlibrary.wrapper.SystemClock;
import com.oszc.bbhmlibrary.utils.LogUtil;
import com.oszc.bbhmlibrary.utils.MainHandler;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.render.Canvas;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.TouchEvent;

import javax.annotation.Nullable;

/**
 * View that displays a {@link DraweeHierarchy}.
 *
 * <p>Hierarchy should be set prior to using this view. See {@code setHierarchy}. Because creating a
 * hierarchy is an expensive operation, it is recommended this be done once per view, typically near
 * creation time.
 *
 * <p>In order to display an image, controller has to be set. See {@code setController}.
 *
 * <p>Although ImageView is subclassed instead of subclassing View directly, this class does not
 * support ImageView's setImageXxx, setScaleType and similar methods. Extending ImageView is a short
 * term solution in order to inherit some of its implementation (padding calculations, etc.). This
 * class is likely to be converted to extend View directly in the future, so avoid using ImageView's
 * methods and properties.
 */
public class DraweeView<DH extends DraweeHierarchy> extends Image implements Component.BindStateChangedListener, Callback, Component.EstimateSizeListener {
    private final String TAG = DraweeView.class.getSimpleName();

    private final AspectRatioMeasure.Spec mMeasureSpec = new AspectRatioMeasure.Spec();
    private float mAspectRatio = 0;
    private DraweeHolder<DH> mDraweeHolder;
    private boolean mInitialised = false;
    private boolean mLegacyVisibilityHandlingEnabled = false;

    private static boolean sGlobalLegacyVisibilityHandlingEnabled = false;
    private Matrix mMatrix;
    private Matrix mDrawMatrix;
    private final RectFloat mTempSrc = new RectFloat();
    private final RectFloat mTempDst = new RectFloat();
    private boolean isDirty = true;

    public static void setGlobalLegacyVisibilityHandlingEnabled(
            boolean legacyVisibilityHandlingEnabled) {
        sGlobalLegacyVisibilityHandlingEnabled = legacyVisibilityHandlingEnabled;
    }

    public DraweeView(Context context) {
        super(context);
        init(context);
    }

    public DraweeView(Context context, AttrSet attrs) {
        super(context, attrs);
        init(context);
    }

    public DraweeView(Context context, AttrSet attrs, String defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }


    /**
     * This method is idempotent so it only has effect the first time it's called
     */
    private void init(Context context) {
        try {
            if (FrescoSystrace.isTracing()) {
                FrescoSystrace.beginSection("DraweeView#init");
            }
            if (mInitialised) {
                return;
            }
            mInitialised = true;
            setClickable(true);
            setEnabled(true);

            setEstimateSizeListener(this);
            mDraweeHolder = DraweeHolder.create(null, context, this);
            setBindStateChangedListener(this);
            //addDrawTask(this::drawToCanvas);
//      mDraweeHolder.onDraw();
//      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//        ColorStateList imageTintList = getImageTintList();
//        if (imageTintList == null) {
//          return;
//        }
//        setColorFilter(imageTintList.getDefaultColor());
//      }
            mLegacyVisibilityHandlingEnabled =
                    sGlobalLegacyVisibilityHandlingEnabled;
//              && context.getApplicationInfo().targetSdkVersion >= 24; // Build.VERSION_CODES.N
            addDrawTask(this::drawToCanvas);
            setTouchEventListener(this::onTouchEvent);
        } finally {
            if (FrescoSystrace.isTracing()) {
                FrescoSystrace.endSection();
            }
        }

    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        LogUtil.error(TAG,
                "onEstimateSize initial ---> width:"+ EstimateSpec.getSize(widthMeasureSpec)+
                "   widthMode:"+EstimateSpec.getMode(widthMeasureSpec)+
                "   height:"+ EstimateSpec.getSize(heightMeasureSpec)+
                "   heightMode:"+EstimateSpec.getMode(heightMeasureSpec));
        onMeasure(widthMeasureSpec,heightMeasureSpec);
        LogUtil.error(TAG,"onEstimateSize before ---> width:"+ EstimateSpec.getSize(mMeasureSpec.width)+"   height:"+ EstimateSpec.getSize(mMeasureSpec.height));
        //setEstimatedSize(mMeasureSpec.width,mMeasureSpec.height);

        zOnMeasure(mMeasureSpec.width,mMeasureSpec.height);

        return true;
    }
    ///////////////////////for test measure start//////////////////////////////////
    private int  mDrawableWidth = 0;
    private int  mDrawableHeight = 0;
    private boolean mAdjustViewBounds = false;
    private int mMaxWidth = Integer.MAX_VALUE;
    private int mMaxHeight = Integer.MAX_VALUE;
    private boolean sCompatAdjustViewBounds = false;

    public void setMaxWidth(int maxWidth) {
        mMaxWidth = maxWidth;
    }

    public int getMaxWidth() {
        return mMaxWidth;
    }

    public boolean getAdjustViewBounds() {
        return mAdjustViewBounds;
    }

    public void setAdjustViewBounds(boolean adjustViewBounds) {
        mAdjustViewBounds = adjustViewBounds;
        if (adjustViewBounds) {
            setScaleMode(ScaleMode.CENTER);
        }
    }
    ////////////////////// 2021.5/19 加入控件测量 //////////////////
    public void zOnMeasure(int widthMeasureSpec, int heightMeasureSpec){
        int w;
        int h;

        // Desired aspect ratio of the view's contents (not including padding)
        float desiredAspect = 0.0f;

        // We are allowed to change the view's width
        boolean resizeWidth = false;

        // We are allowed to change the view's height
        boolean resizeHeight = false;

        final int widthSpecMode = EstimateSpec.getMode(widthMeasureSpec);
        final int heightSpecMode = EstimateSpec.getMode(heightMeasureSpec);

        if ( getImageElement() == null) {
            // If no drawable, its intrinsic size is 0.
            mDrawableWidth = -1;
            mDrawableHeight = -1;
            w = h = 0;
        } else {
            w = mDrawableWidth;
            h = mDrawableHeight;
            if (w <= 0) w = 1;
            if (h <= 0) h = 1;

            // We are supposed to adjust view bounds to match the aspect
            // ratio of our drawable. See if that is possible.
            if (mAdjustViewBounds) {
                resizeWidth = widthSpecMode != EstimateSpec.PRECISE;
                resizeHeight = heightSpecMode != EstimateSpec.PRECISE;

                desiredAspect = (float) w / (float) h;
            }
        }

        final int pleft = getPaddingLeft();
        final int pright = getPaddingRight();
        final int ptop = getPaddingTop();
        final int pbottom = getPaddingBottom();

        int widthSize;
        int heightSize;

        if (resizeWidth || resizeHeight) {
            /* If we get here, it means we want to resize to match the
                drawables aspect ratio, and we have the freedom to change at
                least one dimension.
            */

            // Get the max possible width given our constraints
            widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);

            // Get the max possible height given our constraints
            heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);

            if (desiredAspect != 0.0f) {
                // See what our actual aspect ratio is
                final float actualAspect = (float)(widthSize - pleft - pright) /
                        (heightSize - ptop - pbottom);

                if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {

                    boolean done = false;

                    // Try adjusting width to be proportional to height
                    if (resizeWidth) {
                        int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
                                pleft + pright;

                        // Allow the width to outgrow its original estimate if height is fixed.
                        if (!resizeHeight && !sCompatAdjustViewBounds) {
                            widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
                        }

                        if (newWidth <= widthSize) {
                            widthSize = newWidth;
                            done = true;
                        }
                    }

                    // Try adjusting height to be proportional to width
                    if (!done && resizeHeight) {
                        int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
                                ptop + pbottom;

                        // Allow the height to outgrow its original estimate if width is fixed.
                        if (!resizeWidth && !sCompatAdjustViewBounds) {
                            heightSize = resolveAdjustedSize(newHeight, mMaxHeight,
                                    heightMeasureSpec);
                        }

                        if (newHeight <= heightSize) {
                            heightSize = newHeight;
                        }
                    }
                }
            }
        } else {
            /* We are either don't want to preserve the drawables aspect ratio,
               or we are not allowed to change view dimensions. Just measure in
               the normal way.
            */
            w += pleft + pright;
            h += ptop + pbottom;


            w = Math.max(w, getMinWidth());
            h = Math.max(h, getMinHeight());

            widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
            heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
        }

        LogUtil.error(TAG,"onEstimateSize after---> width:"+ MeasureSpec.getSize(widthSize)
                +"   height:"+ MeasureSpec.getSize(heightSize));
        setEstimatedSize(EstimateSpec.getSizeWithMode(widthSize,EstimateSpec.PRECISE),EstimateSpec.getSizeWithMode(heightSize,EstimateSpec.PRECISE));
    }

    private int resolveAdjustedSize(int desiredSize, int maxSize,
                                    int measureSpec) {
        int result = desiredSize;
        final int specMode = EstimateSpec.getMode(measureSpec);
        final int specSize =  EstimateSpec.getSize(measureSpec);
        switch (specMode) {
            case EstimateSpec.UNCONSTRAINT:
                /* Parent says we can be as big as we want. Just don't be larger
                   than max size imposed on ourselves.
                */
                result = Math.min(desiredSize, maxSize);
                break;
            case EstimateSpec.NOT_EXCEED:
                // Parent says we can be as big as we want, up to specSize.
                // Don't be larger than specSize, and don't be larger than
                // the max size imposed on ourselves.
                result = Math.min(Math.min(desiredSize, specSize), maxSize);
                break;
            case EstimateSpec.PRECISE:
                // No choice. Do what we are told.
                result = specSize;
                break;
        }
        return result;
    }


    public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
        final int specMode = EstimateSpec.getMode(measureSpec);
        final int specSize = EstimateSpec.getSize(measureSpec);
        final int result;
        switch (specMode) {
            case EstimateSpec.NOT_EXCEED:
                if (specSize < size) {
                    result = specSize | 0x01000000 ; //MEASURED_STATE_TOO_SMALL;
                } else {
                    result = size;
                }
                break;
            case EstimateSpec.PRECISE:
                result = specSize;
                break;
            case EstimateSpec.UNCONSTRAINT:
            default:
                result = size;
        }

        return result | (childMeasuredState & EstimateSpec.ESTIMATED_STATE_BIT_MASK);
    }
    ///////////////////////for measure end//////////////////////////////////

    /**
     * Sets the hierarchy.
     */
    public void setHierarchy(DH hierarchy) {
        //Logutil.error(TAG,"setHierarchy");
        mDraweeHolder.setHierarchy(hierarchy);
        Element topLevelDrawable = mDraweeHolder.getTopLevelDrawable();
        //Logutil.error(TAG,"setHierarchy topLevelDrawable:"+topLevelDrawable);
        setImageElement(topLevelDrawable);
    }

    public void onChange(Element element) {
        isDirty = true;
        getContext().getUITaskDispatcher().asyncDispatch(this::invalidate);
    }

    @Override
    public void setLayoutConfig(ComponentContainer.LayoutConfig config) {
        isDirty = true;
        super.setLayoutConfig(config);
        invalidate();
    }

    /**
     * Gets the hierarchy if set, throws NPE otherwise.
     */
    public DH getHierarchy() {
        return mDraweeHolder.getHierarchy();
    }

    /**
     * Returns whether the hierarchy is set or not.
     */
    public boolean hasHierarchy() {
        return mDraweeHolder.hasHierarchy();
    }

    /**
     * Gets the top-level drawable if hierarchy is set, null otherwise.
     */
    @Nullable
    public Element getTopLevelDrawable() {
        return mDraweeHolder.getTopLevelDrawable();
    }

    /**
     * Sets the controller.
     */
    public void setController(@Nullable DraweeController draweeController) {
        mDraweeHolder.setController(draweeController);
        setImageElement(mDraweeHolder.getTopLevelDrawable());
    }

    @Override
    public void setImageElement(Element element) {
        LogUtil.error(TAG,"canvas setImageElement width" + element.getWidth()
                + "; height = " + element.getHeight()+" element:"+element.getClass().getSimpleName());
        //configBounds(element);
        super.setImageElement(element);
        //invalidate();
        element.setCallback(this::onChange);
        if(element instanceof RootShapeElement){
            LogUtil.error(TAG,"setImageElement set hmcallback");
            ((RootShapeElement) element).setHmCallback(this);
        }
    }

    //the framework lack of the ability of configure bounds
    private void configBounds(Element element) {
        if (element == null) {
            return;
        }
        int dwidth = element.getWidth();
        int dheight = element.getHeight();
        if (element instanceof RootShapeElement) {
            dwidth = ((RootShapeElement) element).getIntrinsicWidth();
            dheight = ((RootShapeElement) element).getIntrinsicHeight();
        }

        int vwidth = getWidth() - getPaddingLeft() - getPaddingRight();
        int vheight = getHeight() - getPaddingTop() - getPaddingBottom();
        //Logutil.error(TAG,"configBounds A dwidht:"+dwidth+"  dheight:"+dheight+"   vwidth:"+vwidth+"   vheight:"+vheight);

        final boolean fits = (dwidth < 0 || vwidth == dwidth)
                && (dheight < 0 || vheight == dheight);

        ScaleMode mScaleType = getScaleMode();
        if (dwidth <= 0 || dheight <= 0 || ScaleMode.STRETCH == mScaleType) {
            //Logutil.error(TAG,"configBounds B");
            element.setBounds(0, 0, vwidth, vheight);
            mDrawMatrix = null;
        } else {
            // We need to do the scaling ourself, so have the drawable
            // use its native size.
            //Logutil.error(TAG,"configBounds C");
            element.setBounds(0, 0, dwidth, dheight);

            if (fits) {
                // The bitmap fits exactly, no transform needed.
                element.setBounds(0, 0, vwidth, vheight);
                mDrawMatrix = null;
                //Logutil.error(TAG,"configBounds D");
            } else if (ScaleMode.CENTER == mScaleType) {
                //Logutil.error(TAG,"configBounds E");
                mDrawMatrix = mMatrix;
                mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f),
                        Math.round((vheight - dheight) * 0.5f));

            } else if (ScaleMode.CLIP_CENTER == mScaleType) {
                //Logutil.error(TAG,"configBounds F");
                float scale;
                float dx = 0, dy = 0;
                if (dwidth * vheight > vwidth * dheight) {
                    scale = (float) vheight / (float) dheight;
                    dx = (vwidth - dwidth * scale) * 0.5f;
                } else {
                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * 0.5f;
                }

                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy));
            } else if (ScaleMode.CENTER == mScaleType) {
                mDrawMatrix = mMatrix;
                float scale;
                float dx;
                float dy;
                if (dwidth <= vwidth && dheight <= vheight) {
                    scale = 1.0f;
                } else {
                    scale = Math.min((float) vwidth / (float) dwidth,
                            (float) vheight / (float) dheight);
                }
                dx = Math.round((vwidth - dwidth * scale) * 0.5f);
                dy = Math.round((vheight - dheight * scale) * 0.5f);
                mDrawMatrix.setScale(scale, scale);
                mDrawMatrix.postTranslate(dx, dy);
            } else {
                // Generate the required transform.
                //mTempSrc.fuse(0, 0, dwidth, dheight);

                setRectFloat(mTempSrc, 0, 0, dwidth, dheight);
                setRectFloat(mTempDst, 0, 0, vwidth, vheight);
                mDrawMatrix = mMatrix;

                Matrix.ScaleToFit scaleToFit;
                if(getScaleMode() == ScaleMode.ZOOM_START){
                    scaleToFit = Matrix.ScaleToFit.START;
                }else if(getScaleMode() == ScaleMode.ZOOM_END){
                    scaleToFit = Matrix.ScaleToFit.END;
                }else if(getScaleMode() == ScaleMode.STRETCH){
                    scaleToFit = Matrix.ScaleToFit.FILL;
                }else {
                    scaleToFit = Matrix.ScaleToFit.CENTER;
                }
                mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleToFit);


               // mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
            }
        }
        isDirty = false;
    }

    private void drawToCanvas(Component component, Canvas canvas) {
        if (isDirty) {
            configBounds(getImageElement());
        }
        canvas.save();
        canvas.concat(mDrawMatrix);
        canvas.translate(getPaddingLeft(), getPaddingTop());
        getImageElement().drawToCanvas(canvas);
        canvas.restore();
    }

    private void setRectFloat(RectFloat rectFloat, int l, int t, int r, int b) {
        rectFloat.left = l;
        rectFloat.top = t;
        rectFloat.right = r;
        rectFloat.bottom = b;
    }

    /**
     * Gets the controller if set, null otherwise.
     */
    @Nullable
    public DraweeController getController() {
        return mDraweeHolder.getController();
    }

    /**
     * Returns whether the controller is set or not.
     */
    public boolean hasController() {
        return mDraweeHolder.getController() != null;
    }

    @Override
    public boolean isBoundToWindow() {
        maybeOverrideVisibilityHandling();
        onAttach();
        return super.isBoundToWindow();
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        maybeOverrideVisibilityHandling();
        onAttach();

    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
        maybeOverrideVisibilityHandling();
        onDetach();

    }
//
//  @Override
//  protected void onAttachedToWindow() {
//    super.onAttachedToWindow();
//    maybeOverrideVisibilityHandling();
//    onAttach();
//  }

//  @Override
//  protected void onDetachedFromWindow() {
//    super.onDetachedFromWindow();
//    maybeOverrideVisibilityHandling();
//    onDetach();
//  }

//  @Override
//  public void onStartTemporaryDetach() {
//    super.onStartTemporaryDetach();
//    maybeOverrideVisibilityHandling();
//    onDetach();
//  }
//
//  @Override
//  public void onFinishTemporaryDetach() {
//    super.onFinishTemporaryDetach();
//    maybeOverrideVisibilityHandling();
//    onAttach();
//  }

    /**
     * Called by the system to attach. Subclasses may override.
     */
    protected void onAttach() {
        doAttach();
    }

    /**
     * Called by the system to detach. Subclasses may override.
     */
    protected void onDetach() {
        doDetach();
    }

    /**
     * Does the actual work of attaching.
     *
     * <p>Non-test subclasses should NOT override. Use onAttach for custom code.
     */
    protected void doAttach() {
        mDraweeHolder.onAttach();
    }

    /**
     * Does the actual work of detaching.
     *
     * <p>Non-test subclasses should NOT override. Use onDetach for custom code.
     */
    protected void doDetach() {
        mDraweeHolder.onDetach();
    }


    public boolean onTouchEvent(Component component, TouchEvent event) {
        if (mDraweeHolder.onTouchEvent(event)) {
      //      LogUtil.error(TAG,"onTouchEvent  true");
            return true;
        }
      //  LogUtil.error(TAG,"onTouchEvent false");
        return false;
        
    }

    /**
     * Use this method only when using this class as an ordinary ImageView.
     *
     * @deprecated Use {@link #setController(DraweeController)} instead.
     */
    @Deprecated
    public void setImageDrawable(Element drawable) {
        init(getContext());
        mDraweeHolder.setController(null);
        super.setImageElement(drawable);
    }

    /**
     * Use this method only when using this class as an ordinary ImageView.
     *
     * @deprecated Use {@link #setController(DraweeController)} instead.
     */
//  @Override
    @Deprecated
    public void setImageBitmap(PixelMap bm) {
        init(getContext());
        mDraweeHolder.setController(null);
        super.setPixelMap(bm);
    }

    /**
     * Use this method only when using this class as an ordinary ImageView.
     *
     * @deprecated Use {@link #setController(DraweeController)} instead.
     */
    @Deprecated
    public void setImageResource(int resId) {
        init(getContext());
        mDraweeHolder.setController(null);
        super.setPixelMap(resId);
    }

//  /**
//   * Use this method only when using this class as an ordinary ImageView.
//   *
//   * @deprecated Use {@link #setController(DraweeController)} instead.
//   */
//  @Override
//  @Deprecated
//  public void setImageURI(Uri uri) {
//    init(getContext());
//    mDraweeHolder.setController(null);
//    super.setImageURI(uri);
//  }

    /**
     * Sets the desired aspect ratio (w/h).
     */
    public void setAspectRatio(float aspectRatio) {
        //Logutil.error(TAG,"setAspectRatio A");
        if (aspectRatio == mAspectRatio) {
            //Logutil.error(TAG,"setAspectRatio B");
            return;
        }
        //Logutil.error(TAG,"setAspectRatio C");
        mAspectRatio = aspectRatio;
        postLayout();
    }

    /**
     * Gets the desired aspect ratio (w/h).
     */
    public float getAspectRatio() {
        return mAspectRatio;
    }

    public void setLegacyVisibilityHandlingEnabled(boolean legacyVisibilityHandlingEnabled) {
        mLegacyVisibilityHandlingEnabled = legacyVisibilityHandlingEnabled;
    }

    @Override
    public void postLayout() {
        mMeasureSpec.width = getWidth();
        mMeasureSpec.height =getHeight();
        AspectRatioMeasure.updateMeasureSpec(
                mMeasureSpec,
                mAspectRatio,
                getLayoutConfig(),
                getPaddingLeft() + getPaddingRight(),
                getPaddingTop() + getPaddingBottom());
        maybeOverrideVisibilityHandling();
        super.postLayout();
        ComponentContainer.LayoutConfig layoutConfig = getLayoutConfig();
        layoutConfig.width = EstimateSpec.getSize(mMeasureSpec.width);
        layoutConfig.height =EstimateSpec.getSize( mMeasureSpec.height);
        setLayoutConfig(layoutConfig);
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mMeasureSpec.width = widthMeasureSpec;
        mMeasureSpec.height = heightMeasureSpec;
        AspectRatioMeasure.updateMeasureSpec(
                mMeasureSpec,
                mAspectRatio,
                getLayoutConfig(),
                getPaddingLeft() + getPaddingRight(),
                getPaddingTop() + getPaddingBottom());
    }

    //  @Override
    protected void onVisibilityChanged(Component changedView, int visibility) {
        //super.onVisibilityChanged(changedView, visibility);
        maybeOverrideVisibilityHandling();
    }


    private void maybeOverrideVisibilityHandling() {
        //Logutil.error(TAG,"maybeOverrideVisibilityHandling A");
        if (mLegacyVisibilityHandlingEnabled) {
            Element drawable = getImageElement();
            if (drawable != null) {
                //Logutil.error(TAG,"maybeOverrideVisibilityHandling B  getVisibility:"+(getVisibility()==VISIBLE));
                drawable.setVisible(getVisibility() == VISIBLE, false);
            }
        }
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this)
                .add("holder", mDraweeHolder != null ? mDraweeHolder.toString() : "<no holder set>")
                .toString();
    }

    @Override
    public void invalidateDrawable(Element who) {
    //    LogUtil.error(TAG,"canvas invalidateDrawable ");
        onChange(who);
    }

    @Override
    public void scheduleDrawable(Element who, Runnable what, long when) {
        //LogUtil.error(TAG,"canvas scheduleDrawable A");
        final long delay = when - SystemClock.uptimeMillis();
        if(what!=null&& delay > 0) {

         //   LogUtil.error(TAG,"canvas scheduleDrawable B "+ when+ "   delay:"+delay);
            MainHandler.removeTask(what);
            MainHandler.postDelay(what, delay);
        }else{
          //  LogUtil.error(TAG,"canvas scheduleDrawable C");
        }
    }

    @Override
    public void unscheduleDrawable(Element who, Runnable what) {
  //      LogUtil.error(TAG,"canvas unscheduleDrawable ");
        MainHandler.removeTask(what);
    }
}
